/*
 * Syntelos 'SX'
 * Copyright (C) 1998, 2007  John Pritchard.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */
package syntelos.sx;

import alto.lang.Message;


/**
 * <p> Network logging. </p>
 * 
 * @author jdp
 * @version 20080215/2113
 * @since 1.6
 */
public final class Log
    extends SX.Daemon.Log
{


    public final static boolean Include(Throwable thrown){
        if (thrown instanceof java.io.IOException){
            java.lang.String msg = thrown.getMessage();
            if ("Connection reset by peer".equals(msg))
                return false;
            else if ("Broken pipe".equals(msg))
                return false;
        }
        return true;
    }


    private final boolean enabled;

    private java.io.OutputStream echo;

    private Message.Queue queue;

    private boolean neednote = true;

    private int depth;

    private final LogDepth statistic;


    Log(Server server){
        super(server.getName()+"/Log");
        this.enabled = server.isLogEnabled();
        if (server.isLogEcho())
            this.echo = System.err;
        this.statistic = new LogDepth(this);
    }


    public final LogDepth getStatistic(){
        return this.statistic;
    }
    public final int getDepth(){
        return this.depth;
    }
    public final void pushWrite(Request request, Response response){
        if (this.enabled){
            try {
                if (response instanceof syntelos.sx.methods.Error){
                    syntelos.sx.methods.Error error = (syntelos.sx.methods.Error)response;
                    if (error.hasError()){
                        this.pushWrite(request,response,error.getError());
                        return;
                    }
                }
                synchronized(this){
                    this.queue = new LogRR(this.queue,request,response);
                    this.depth += 1;
                    if (this.neednote)
                        this.notify();
                }
            }
            catch (java.lang.Throwable ignore){
                ignore.printStackTrace();
            }
        }
    }
    public final void pushWrite(Request request, Response response, Throwable thrown){
        if (this.enabled){
            try {
                if (Include(thrown)){
                    //thrown.printStackTrace();
                    synchronized(this){
                        this.queue = new LogRX(this.queue,request,response,thrown);
                        this.depth += 1;
                        if (this.neednote)
                            this.notify();
                    }
                }
            }
            catch (java.lang.Throwable ignore){
                ignore.printStackTrace();
            }
        }
    }
    public final void pushOpen(Server server){
        if (this.enabled){
            synchronized(this){
                this.queue = new LogSO(this.queue,server);
                this.depth += 1;
                if (this.neednote)
                    this.notify();
            }
        }
    }
    public final void pushClose(Server server){
        if (this.enabled){
            synchronized(this){
                this.queue = new LogSC(this.queue,server);
                this.depth += 1;
                if (this.neednote)
                    this.notify();
            }
        }
    }
    private final synchronized alto.io.Message popMessage(){
        alto.io.Message.Queue m = this.queue;
        if (null != m){
            this.queue = m.pop();
            this.depth -= 1;
        }
        return m;
    }
    public final void run(){
        java.io.OutputStream echo = this.echo;
        boolean useecho = (null != echo);
        while (true){
            try {
                alto.io.Message msg = this.popMessage();
                if (null == msg){
                    synchronized(this){
                        this.neednote = true;
                        this.wait();
                        this.neednote = false;
                    }
                }
                else {
                    msg.formatMessage();

                    if (msg.isPersistent()){
                        try {
                            msg.writeMessage();
                        }
                        catch (java.io.IOException iox){
                            iox.printStackTrace();
                        }
                    }
                    //
                    if (useecho){
                        try {
                            synchronized(echo){
                                echo.write(msg.getBuffer());
                                echo.flush();
                            }
                        }
                        catch (java.io.IOException iox){
                            iox.printStackTrace();
                        }
                    }
                }
            }
            catch (InterruptedException inx){
                return;
            }
            catch (OutOfMemoryError exc){
                java.lang.System.gc();
            }
            catch (Throwable exc){
                exc.printStackTrace();
            }
        }
    }
}
